#include "HttpContext.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
#include <stdexcept>
#include <cassert>

HttpContext::HttpContext(std::unordered_map<size_t, GlobalExceptionHandle> &exceptHandles)
    : exceptHandles(exceptHandles) {
}

HttpContext::~HttpContext() {
    clear();
}

void HttpContext::clear() {
    m_request.reset();
    m_response.reset();
}

bool HttpContext::handle() {
    if (callback) {
        bool bRes = true;
        try {
            callback(m_request.get(), m_response.get());
        } catch (...) {
            bRes = exceptionHandle(std::current_exception());
        }
        respHandle();
        return bRes;
    }
    return false;
}

bool HttpContext::exceptionHandle(std::exception_ptr eptr) {
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch (const std::exception &e) {
        size_t code = typeid(e).hash_code();
        auto iter = exceptHandles.find(code);
        if (iter != exceptHandles.end()) {
            return iter->second(e.what(), m_request.get(), m_response.get());
        }
        //LOG(ERROR) << e.what();
    }
    return false;
}

void HttpContext::writeNotFount() {
    if (httpServer) {
        const std::string notFount = "404 NOT FOUNT.";
        const std::string strNotFountLength = std::to_string(notFount.length());
        THeader header[] = {{"Content-Type",   "text/plain"},
                            {"Content-Length", strNotFountLength.data()}};
        int iHeaderCount = sizeof(header) / sizeof(THeader);
        httpServer->SendResponse(m_connId,
                                 HSC_NOT_FOUND,
                                 "",
                                 header, iHeaderCount,
                                 reinterpret_cast<const unsigned char *>(notFount.data()),
                                 notFount.length());
        if (!httpServer->IsKeepAlive(m_connId))
            httpServer->Release(m_connId);
    }
}

void HttpContext::respHandle()
{
    assert(m_response);
    if (httpServer) {
        std::string strBody = m_response->m_buffer.str();
        std::string strBodyLength = std::to_string(strBody.length());
        std::vector<THeader> headers;
        for (auto& iter : m_response->m_mapHeader) {
            headers.push_back({ iter.first.c_str(), iter.second.c_str() });
        }
        
        int iHeaderCount = headers.size();
        httpServer->SendResponse(m_connId,
            m_response->m_statusCode,
            "OK",
            headers.data(), iHeaderCount,
            reinterpret_cast<const unsigned char*>(strBody.data()),
            strBody.length());
        if (!httpServer->IsKeepAlive(m_connId))
            httpServer->Release(m_connId);
    }
}

void HttpContext::wRequestBody(const char *buf, int len) {
    assert(m_request);
    m_request->writeData(buf, len);
}
